/******************************************************************************
 * JBoss, a division of Red Hat                                               *
 * Copyright 2011, Red Hat Middleware, LLC, and individual                    *
 * contributors as indicated by the @authors tag. See the                     *
 * copyright.txt in the distribution for a full listing of                    *
 * individual contributors.                                                   *
 *                                                                            *
 * This is free software; you can redistribute it and/or modify it            *
 * under the terms of the GNU Lesser General Public License as                *
 * published by the Free Software Foundation; either version 2.1 of           *
 * the License, or (at your option) any later version.                        *
 *                                                                            *
 * This software is distributed in the hope that it will be useful,           *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU           *
 * Lesser General Public License for more details.                            *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public           *
 * License along with this software; if not, write to the Free                *
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA         *
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.                   *
 ******************************************************************************/
package org.jboss.gatein.qa.picketlink.hibernate.test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import junit.framework.TestCase;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.picketlink.idm.api.IdentitySessionFactory;
import org.picketlink.idm.api.UnsupportedCriterium;
import org.picketlink.idm.api.cfg.IdentityConfiguration;
import org.picketlink.idm.common.exception.IdentityException;
import org.picketlink.idm.impl.api.IdentitySearchCriteriaImpl;
import org.picketlink.idm.impl.api.PasswordCredential;
import org.picketlink.idm.impl.api.SimpleAttribute;
import org.picketlink.idm.impl.api.session.IdentitySessionImpl;
import org.picketlink.idm.impl.api.session.context.IdentitySessionContext;
import org.picketlink.idm.impl.configuration.IdentityConfigurationImpl;
import org.picketlink.idm.impl.configuration.jaxb2.JAXB2IdentityConfiguration;
import org.picketlink.idm.impl.types.SimpleIdentityObject;
import org.picketlink.idm.impl.types.SimpleIdentityObjectRelationshipType;
import org.picketlink.idm.impl.types.SimpleIdentityObjectType;
import org.picketlink.idm.spi.configuration.metadata.IdentityConfigurationMetaData;
import org.picketlink.idm.spi.model.IdentityObject;
import org.picketlink.idm.spi.model.IdentityObjectAttribute;
import org.picketlink.idm.spi.model.IdentityObjectRelationshipType;
import org.picketlink.idm.spi.model.IdentityObjectType;
import org.picketlink.idm.spi.repository.IdentityStoreRepository;
import org.picketlink.idm.spi.store.IdentityStoreInvocationContext;

/**
 * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
 * @version $Revision$
 */
public class PicketlinkExampleTestCase extends TestCase
{
   
   private static Logger log = Logger.getLogger(PicketlinkExampleTestCase.class.getName());
   
   private IdentitySessionFactory identitySessionFactory;
   
   public void setUp()
   {
      try
      {
         System.out.println("test hibernate invoked.");
      
         IdentityConfigurationMetaData configMD =
            JAXB2IdentityConfiguration.createConfigurationMetaData(Thread.currentThread().getContextClassLoader().getResourceAsStream("configuration/picketlink-idm.xml"));         
      
         IdentityConfiguration identityConfiguration = new IdentityConfigurationImpl().configure(configMD);
         
         Configuration config = new Configuration().configure("configuration/hibernate.cfg.xml");
         SessionFactory sessionFactory = config.buildSessionFactory();
         identityConfiguration.getIdentityConfigurationRegistry().register(sessionFactory, "hibernateSessionFactory");
         
         identitySessionFactory = identityConfiguration.buildIdentitySessionFactory();
         
         System.out.println("IdentitySessionFactory built successfully!");
      }
      catch (IdentityException ice)
      {
         throw new RuntimeException(ice);
      }
   }
   
   public void tstCreatingUsersAndGroups()
   {
      try
      {
         identitySessionFactory.getCurrentIdentitySession("idm_realm").beginTransaction(); 
         
         IdentitySessionContext iSessionContext = ((IdentitySessionImpl)identitySessionFactory.getCurrentIdentitySession("idm_realm")).getSessionContext();
         IdentityStoreRepository repository = iSessionContext.getIdentityStoreRepository();
         IdentityStoreInvocationContext iStoreInvContext = iSessionContext.resolveStoreInvocationContext();
         
         // creating user (without attributes)
         IdentityObject demo = repository.createIdentityObject(iStoreInvContext, "demo", new SimpleIdentityObjectType("USER"));
                  
         // creating user root (with attributes)
         Map<String, String[]> attrMap = new HashMap<String, String[]>();
         attrMap.put("password", new String[] { "gtnENC"} );
         attrMap.put("firstName", new String[] { "Root"} );
         attrMap.put("lastName", new String[] { "Root"} );
         attrMap.put("email", new String[] { "root@seznam.cz"} );                  
         IdentityObject root = repository.createIdentityObject(iStoreInvContext, "root", new SimpleIdentityObjectType("USER"), attrMap);
         
         // creating user mary         
         attrMap.put("password", new String[] { "gtnENC"} );
         attrMap.put("firstName", new String[] { "Mary"} );
         attrMap.put("lastName", new String[] { "Kelly"} );
         attrMap.put("email", new String[] { "mary@seznam.cz"} );                  
         IdentityObject mary = repository.createIdentityObject(iStoreInvContext, "mary", new SimpleIdentityObjectType("USER"), attrMap);         
                  
         // creating groups with and without attributes               
         IdentityObject platform = repository.createIdentityObject(iStoreInvContext, "platform", new SimpleIdentityObjectType("GROUP"));
         IdentityObject partners = repository.createIdentityObject(iStoreInvContext, "partners", new SimpleIdentityObjectType("GROUP"));
                   
         attrMap.put("label", new String[] { "users"} );
         attrMap.put("description", new String[] { "Users group description"} );            
         IdentityObject users = repository.createIdentityObject(iStoreInvContext, "users", new SimpleIdentityObjectType("GROUP"), attrMap);
         
         attrMap.put("label", new String[] { "administrators"} );
         attrMap.put("description", new String[] { "Admiistrators group description"} );            
         IdentityObject administrators = repository.createIdentityObject(iStoreInvContext, "administrators", new SimpleIdentityObjectType("GROUP"), attrMap);         
         
         // now creating unnamed relationships among groups
         IdentityObjectRelationshipType relTypeUnnamed = new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_MEMBERSHIP");
         repository.createRelationship(iStoreInvContext, platform, users, relTypeUnnamed, null, false);
         repository.createRelationship(iStoreInvContext, platform, administrators, relTypeUnnamed, null, false);

         // now creating named relationships among users and groups
         IdentityObjectRelationshipType relTypeNamed = new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE");
         repository.createRelationship(iStoreInvContext, users, root, relTypeNamed, null, false);
         repository.createRelationship(iStoreInvContext, users, mary, relTypeNamed, null, false);
         repository.createRelationship(iStoreInvContext, administrators, root, relTypeNamed, null, false);                  
         
         identitySessionFactory.getCurrentIdentitySession("idm_realm").getTransaction().commit();
      }
      catch (IdentityException ie)
      {
         throw new RuntimeException(ie);
      }
   }
   
   public void tstFinding()
   {
      try
      {
         identitySessionFactory.getCurrentIdentitySession("idm_realm").beginTransaction();  
         
         IdentitySessionContext iSessionContext = ((IdentitySessionImpl)identitySessionFactory.getCurrentIdentitySession("idm_realm")).getSessionContext();
         IdentityStoreRepository repository = iSessionContext.getIdentityStoreRepository();
         IdentityStoreInvocationContext iStoreInvContext = iSessionContext.resolveStoreInvocationContext();                          
         
         // find by id
         System.out.println();
         System.out.println("FIND BY ID");
         System.out.println("OBJECT: " + repository.findIdentityObject(iStoreInvContext, "1"));
         System.out.println("OBJECT: " + repository.findIdentityObject(iStoreInvContext, "3"));
         System.out.println("OBJECT: " + repository.findIdentityObject(iStoreInvContext, "4"));
         
         // find by name
         System.out.println();
         System.out.println("FIND BY NAME");
         System.out.println("OBJECT: " + repository.findIdentityObject(iStoreInvContext, "root", new SimpleIdentityObjectType("USER")));
         System.out.println("OBJECT: " + repository.findIdentityObject(iStoreInvContext, "users", new SimpleIdentityObjectType("SomethingDifferent")));
         
         // find by unique attribute
         System.out.println();
         System.out.println("FIND BY UNIQUE ATTRIBUTE");
         System.out.println("OBJECT: " + repository.findIdentityObjectByUniqueAttribute(iStoreInvContext, new SimpleIdentityObjectType("USER"), new SimpleAttribute("email", "root@seznam.cz")));
         System.out.println("OBJECT: " + repository.findIdentityObjectByUniqueAttribute(iStoreInvContext, new SimpleIdentityObjectType("GRROP"), new SimpleAttribute("label", "administrators")));
         
         // find by criteria
         System.out.println();
         System.out.println("FIND BY SEARCH CRITERIA");
         IdentitySearchCriteriaImpl searchCriteria = new IdentitySearchCriteriaImpl();
         searchCriteria.attributeValuesFilter("email", new String[] { "%" });
         searchCriteria.sortAttributeName("firstName");
         System.out.println("OBJECTS: " + repository.findIdentityObject(iStoreInvContext, new SimpleIdentityObjectType("USER"), searchCriteria));
         
         searchCriteria.nameFilter("root");         
         System.out.println("OBJECT: " + repository.findIdentityObject(iStoreInvContext, new SimpleIdentityObjectType("USER"), searchCriteria));
         System.out.println("OBJECTS (EMPTY): " + repository.findIdentityObject(iStoreInvContext, new SimpleIdentityObjectType("USR"), searchCriteria));
         
         IdentitySearchCriteriaImpl searchCriteria2 = new IdentitySearchCriteriaImpl();
         searchCriteria2.attributeValuesFilter("label", new String[] { "users" });         
         System.out.println("OBJECT: " + repository.findIdentityObject(iStoreInvContext, new SimpleIdentityObjectType("GROP"), searchCriteria2));
         
         // find by parent/child
         System.out.println();
         System.out.println("FIND BY PARENT / CHILD");
         
         IdentitySearchCriteriaImpl searchCriteria3 = new IdentitySearchCriteriaImpl();
         System.out.println("CHILDRENS (USERS) OF 'PLATFORM': " + repository.findIdentityObject(iStoreInvContext, 
                              new SimpleIdentityObject("platform", new SimpleIdentityObjectType("GROP")), 
                              new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE"), 
                              true, searchCriteria3));
         
         System.out.println("CHILDRENS (GROUPS) OF 'PLATFORM': " + repository.findIdentityObject(iStoreInvContext, 
               new SimpleIdentityObject("platform", new SimpleIdentityObjectType("GROP")), 
               new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_MEMBERSHIP"), 
               true, searchCriteria3));         
         
         System.out.println("CHILDRENS OF 'USERS': " + repository.findIdentityObject(iStoreInvContext, 
               new SimpleIdentityObject("users", new SimpleIdentityObjectType("GROP")), 
               new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE"), 
               true, searchCriteria3));      
         
         System.out.println("PARENT OF 'USERS': " + repository.findIdentityObject(iStoreInvContext, 
               new SimpleIdentityObject("users", new SimpleIdentityObjectType("GROP")), 
               new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE"), 
               false, searchCriteria3));         
         
         System.out.println("PARENTS OF 'ROOT': " + repository.findIdentityObject(iStoreInvContext, 
               new SimpleIdentityObject("root", new SimpleIdentityObjectType("USER")), 
               new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE"), 
               false, searchCriteria3));  
         
         searchCriteria3.attributeValuesFilter("email", new String[] { "root@seznam.cz" });
         searchCriteria3.nameFilter("root");
         searchCriteria3.sortAttributeName("email");
         System.out.println("CHILDRENS OF 'USERS' WITH EMAIL root@seznam.cz : " + repository.findIdentityObject(iStoreInvContext, 
               new SimpleIdentityObject("users", new SimpleIdentityObjectType("GROP")), 
               new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE"), 
               true, searchCriteria3));           
         
         identitySessionFactory.getCurrentIdentitySession("idm_realm").getTransaction().commit();         
      }
      catch (IdentityException ie)
      {
         throw new RuntimeException(ie);
      } 
      catch (UnsupportedCriterium uc)
      {
         throw new RuntimeException(uc);
      }
   }
   
   public void tstRelationshipOperations()
   {
      try
      {
         identitySessionFactory.getCurrentIdentitySession("idm_realm").beginTransaction();    
         
         IdentitySessionContext iSessionContext = ((IdentitySessionImpl)identitySessionFactory.getCurrentIdentitySession("idm_realm")).getSessionContext();
         IdentityStoreRepository repository = iSessionContext.getIdentityStoreRepository();
         IdentityStoreInvocationContext iStoreInvContext = iSessionContext.resolveStoreInvocationContext();
         
         System.out.println("");
         System.out.println("IDENTITY USERS COUNT: " + repository.getIdentityObjectsCount(iStoreInvContext, new SimpleIdentityObjectType("USER")));       
         System.out.println("IDENTITY GROUPS COUNT: " + repository.getIdentityObjectsCount(iStoreInvContext, new SimpleIdentityObjectType("SOMETH")));
         
         System.out.println("");
         System.out.println("RELATIONSHIP NAME PROPERTIES (manager): " + repository.getRelationshipNameProperties(iStoreInvContext, "manager"));
         
         System.out.println("");
         System.out.println("RELATIONSHIP NAMES : " + repository.getRelationshipNames(iStoreInvContext, null));
         IdentitySearchCriteriaImpl searchCriteria1 = new IdentitySearchCriteriaImpl();
         searchCriteria1.nameFilter("manager");
         System.out.println("RELATIONSHIP NAMES (manager only) : " + repository.getRelationshipNames(iStoreInvContext, searchCriteria1));
         
         System.out.println("");
         System.out.println("RELATIONSHIP NAMES (platform): " + repository.getRelationshipNames(iStoreInvContext, new SimpleIdentityObject("platform", new SimpleIdentityObjectType("GROUP")), null));
         
         IdentityObject mary = new SimpleIdentityObject("mary", new SimpleIdentityObjectType("USER"));
         IdentityObject platform = new SimpleIdentityObject("platform", new SimpleIdentityObjectType("GROUP"));
         IdentityObject users = new SimpleIdentityObject("users", new SimpleIdentityObjectType("GROUP"));
         System.out.println("");
         System.out.println("RESOLVE RELATIONSHIPS (platformm john): " + repository.resolveRelationships(iStoreInvContext, platform, mary, new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE")));
         System.out.println("RESOLVE RELATIONSHIPS (users john): " + repository.resolveRelationships(iStoreInvContext, users, mary, new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE")));
         System.out.println("RESOLVE RELATIONSHIPS (platformm users): " + repository.resolveRelationships(iStoreInvContext, platform, users, new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_MEMBERSHIP")));
         
         IdentityObjectRelationshipType namedType = new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE");
         IdentityObjectRelationshipType unnamedType = new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_MEMBERSHIP");
         System.out.println("");
         System.out.println("RESOLVE RELATIONSHIPS (child groups of platform): " + repository.resolveRelationships(iStoreInvContext, platform, unnamedType, true, false, null));
         System.out.println("RESOLVE RELATIONSHIPS (child users of 'users' group): " + repository.resolveRelationships(iStoreInvContext, users, namedType, true, false, null));
         System.out.println("RESOLVE RELATIONSHIPS (parents of 'mary'): " + repository.resolveRelationships(iStoreInvContext, mary, namedType, false, false, null));
         System.out.println("RESOLVE RELATIONSHIPS (parents of 'mary' with restricted membership 'member'): " + repository.resolveRelationships(iStoreInvContext, mary, namedType, false, true, "member"));
         
         identitySessionFactory.getCurrentIdentitySession("idm_realm").getTransaction().commit();         
      }
      catch (IdentityException ie)
      {
         throw new RuntimeException(ie);
      } 
      catch (UnsupportedCriterium uc)
      {
         throw new RuntimeException(uc);
      }
   }     
   
   public void tstAttributesAndPasswords()
   {
      try
      {
         identitySessionFactory.getCurrentIdentitySession("idm_realm").beginTransaction(); 
         
         
         IdentitySessionContext iSessionContext = ((IdentitySessionImpl)identitySessionFactory.getCurrentIdentitySession("idm_realm")).getSessionContext();
         IdentityStoreRepository repository = iSessionContext.getIdentityStoreRepository();
         IdentityStoreInvocationContext iStoreInvContext = iSessionContext.resolveStoreInvocationContext();
         
         // test password
         IdentityObjectType userType = new SimpleIdentityObjectType("USER");
         IdentityObject demo = new SimpleIdentityObject("demo", userType);
         IdentityObject mary = new SimpleIdentityObject("mary", userType);
         
         System.out.println("");
         System.out.println("VALIDATE PASSWORD (demo) - (should be false): " + repository.validateCredential(iStoreInvContext, demo, new PasswordCredential("gtnrr")));       
         repository.updateCredential(iStoreInvContext, demo, new PasswordCredential("gtnrr"));     
         System.out.println("VALIDATE PASSWORD (demo) - (should be true): " + repository.validateCredential(iStoreInvContext, demo, new PasswordCredential("gtnrr")));
         
         // add attributes
         List<IdentityObjectAttribute> attributes = new ArrayList<IdentityObjectAttribute>();
         attributes.add(new SimpleAttribute("firstName", "DemoFN"));
         attributes.add(new SimpleAttribute("lastName", "DemoLN"));
         IdentityObjectAttribute[] attributess = attributes.toArray( new IdentityObjectAttribute[] {});
         repository.addAttributes(iStoreInvContext, demo, attributess);
         
         System.out.println("");
         System.out.println("FIND IDENTITY OBJECT BY UNIQUE ATTRIBUTE: " + repository.findIdentityObjectByUniqueAttribute(iStoreInvContext, userType, new SimpleAttribute("email", "mary@seznam.cz")));
         System.out.println("GET ATTRIBUTE (MARY, EMAIL): " + repository.getAttribute(iStoreInvContext, mary, "email").getValue());
         System.out.println("GET ATTRIBUTES (DEMO): " + repository.getAttributes(iStoreInvContext, demo));
         
         repository.removeAttributes(iStoreInvContext, demo, new String[] { "firstName", "lastName"});
         System.out.println("GET ATTRIBUTES (DEMO): " + repository.getAttributes(iStoreInvContext, demo));
         
         identitySessionFactory.getCurrentIdentitySession("idm_realm").getTransaction().commit();   
      }
      catch (IdentityException ie)
      {
         throw new RuntimeException(ie);
      }          
   } 
      
   public void tstRemoving()
   {
      try
      {
         identitySessionFactory.getCurrentIdentitySession("idm_realm").beginTransaction(); 
         
         
         IdentitySessionContext iSessionContext = ((IdentitySessionImpl)identitySessionFactory.getCurrentIdentitySession("idm_realm")).getSessionContext();
         IdentityStoreRepository repository = iSessionContext.getIdentityStoreRepository();
         IdentityStoreInvocationContext iStoreInvContext = iSessionContext.resolveStoreInvocationContext();
         
         IdentityObjectRelationshipType unnamedType = new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_MEMBERSHIP");
         IdentityObjectRelationshipType namedType = new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE");
         IdentityObject root = new SimpleIdentityObject("root", new SimpleIdentityObjectType("USER"));
         IdentityObject users = new SimpleIdentityObject("users", new SimpleIdentityObjectType("GROUP"));
         IdentityObject administrators = new SimpleIdentityObject("administrators", new SimpleIdentityObjectType("GROUP"));
         IdentityObject platform = new SimpleIdentityObject("platform", new SimpleIdentityObjectType("GROUP"));
         
         repository.removeRelationship(iStoreInvContext, users, root, namedType, null);
         repository.removeRelationship(iStoreInvContext, platform, users, unnamedType, null);
         repository.removeRelationships(iStoreInvContext, administrators, root, false);
         
         repository.removeIdentityObject(iStoreInvContext, root);
         repository.removeIdentityObject(iStoreInvContext, new SimpleIdentityObject("demo", new SimpleIdentityObjectType("USER")));
         repository.removeIdentityObject(iStoreInvContext, new SimpleIdentityObject("mary", new SimpleIdentityObjectType("USER")));
         
         repository.removeIdentityObject(iStoreInvContext, new SimpleIdentityObject("platform", new SimpleIdentityObjectType("GROUP")));
         repository.removeIdentityObject(iStoreInvContext, new SimpleIdentityObject("partners", new SimpleIdentityObjectType("GROUP")));         
         repository.removeIdentityObject(iStoreInvContext, new SimpleIdentityObject("users", new SimpleIdentityObjectType("GROUP")));
         repository.removeIdentityObject(iStoreInvContext, new SimpleIdentityObject("administrators", new SimpleIdentityObjectType("GROUP")));                  
         
         identitySessionFactory.getCurrentIdentitySession("idm_realm").getTransaction().commit();   
      }
      catch (IdentityException ie)
      {
         throw new RuntimeException(ie);
      }                      
   }
   
   public void testIntegration()
   {
         try
         {
            identitySessionFactory.getCurrentIdentitySession("idm_realm").beginTransaction();  
            
            IdentitySessionContext iSessionContext = ((IdentitySessionImpl)identitySessionFactory.getCurrentIdentitySession("idm_realm")).getSessionContext();
            IdentityStoreRepository repository = iSessionContext.getIdentityStoreRepository();
            IdentityStoreInvocationContext iStoreInvContext = iSessionContext.resolveStoreInvocationContext();
            
            // find objects which don't exists         
            System.out.println();
            System.out.println("FIND UNKNOWN OBJECTS: " + repository.findIdentityObject(iStoreInvContext, "platform", new SimpleIdentityObjectType("root_type")));
            repository.findIdentityObject(iStoreInvContext, new SimpleIdentityObject("platform", new SimpleIdentityObjectType("root_type")), 
                  new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_MEMBERSHIP"), false, null);
            
            System.out.println("RESOLVE RELATIONSHIPS: " + repository.resolveRelationships(iStoreInvContext, new SimpleIdentityObject("john", new SimpleIdentityObjectType("USER")), 
                  new SimpleIdentityObjectRelationshipType("JBOSS_IDENTITY_ROLE"), false, true, null));
           
            identitySessionFactory.getCurrentIdentitySession("idm_realm").getTransaction().commit();   
         }
         catch (IdentityException ie)
         {
            throw new RuntimeException(ie);
         }               
   }
   

}

